package cn.wolfcode.wolf2w.business.service.impl;

import cn.wolfcode.wolf2w.api.RemoteDestinationService;
import cn.wolfcode.wolf2w.api.domain.*;
import cn.wolfcode.wolf2w.business.mapper.AnswerAttentionMapper;
import cn.wolfcode.wolf2w.business.mapper.AnswerMapper;
import cn.wolfcode.wolf2w.business.mapper.QuestionAttentionMapper;
import cn.wolfcode.wolf2w.business.mapper.QuestionMapper;
import cn.wolfcode.wolf2w.business.query.QuestionQuery;
import cn.wolfcode.wolf2w.business.service.IQuestionService;
import cn.wolfcode.wolf2w.business.util.DateUtil;
import cn.wolfcode.wolf2w.business.vo.QuestionCreateVO;
import cn.wolfcode.wolf2w.common.core.context.SecurityContextHolder;
import cn.wolfcode.wolf2w.common.core.exception.ServiceException;
import cn.wolfcode.wolf2w.common.redis.service.RedisService;
import cn.wolfcode.wolf2w.common.redis.util.RedisKeys;
import cn.wolfcode.wolf2w.member.api.RemoteUserInfoService;
import cn.wolfcode.wolf2w.member.api.domain.UserInfo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 问答Service业务层处理
 *
 * @author 浪兎兎
 * @date 2025-06-07
 */
@Service
@Transactional
public class QuestionServiceImpl extends ServiceImpl<QuestionMapper, Question> implements IQuestionService {

    @Autowired
    private RemoteUserInfoService userInfoService;

    @Autowired
    private RemoteDestinationService destinationService;

    @Autowired
    private AnswerMapper answerMapper;

    @Autowired
    private QuestionAttentionMapper questionAttentionMapper;

    @Autowired
    private AnswerAttentionMapper answerAttentionMapper;

    @Autowired
    private RedisService redisService;

    @Autowired
    private AmqpTemplate amqpTemplate;


    @Override
    public IPage<Question> queryPage(QuestionQuery qo) {
        IPage<Question> page = new Page<>(qo.getCurrentPage(), qo.getPageSize());
        LambdaQueryWrapper<Question> queryWrapper = new QueryWrapper<Question>().lambda();
        if (!Question.NO_DRAFT_FILTER.equals(qo.getIsDraft())) {
            queryWrapper.eq(Question::getIsDraft, qo.getIsDraft());
        }
        queryWrapper.like(Question::getTitle, qo.getTitle());
        queryWrapper.like(Question::getAuthorName, qo.getAuthorName());
        queryWrapper.like(Question::getDestinationName, qo.getDestinationName());
        return baseMapper.selectPage(page, queryWrapper);
    }

    @Override
    public void create(QuestionCreateVO vo) {
        // 获取当前用户信息
        Long userId = SecurityContextHolder.getUserId();
        UserInfo user = userInfoService.getOne(userId, "inner").getData();
        // 获取目的地信息
        Destination dest = destinationService.getOne(vo.getDestId(), "inner").getData();
        // 插入
        Question question = new Question();
        question.setTitle(vo.getTitle());
        question.setAuthorName(user.getNickname());
        question.setDetailDoubt(vo.getContents());
        question.setLevel(user.getLevel());
        question.setDestinationId(vo.getDestId());
        question.setDestinationName(dest.getName());
        question.setIsDraft(vo.getIsDraft());
        question.setCreateTime(new Date());

        baseMapper.insert(question);
    }

    @Override
    public Question selectById(Long id) {
        if (id == null) {
            throw new ServiceException("参数非法");
        }
        Question question = baseMapper.selectById(id);
        if (question == null) {
            throw new ServiceException("参数非法");
        }
        // 浏览量
        String key = RedisKeys.QUESTION_STATUS_HASH.join(id.toString());
        if (!redisService.hasKey(key)) {
            // 如果没缓存，那么添加缓存
            HashMap<String, Object> cache = new HashMap<String, Object>() {{
                this.put("viewNum", question.getViewNum());
                this.put("count", question.getCount());
                this.put("id", question.getId());
            }};
            redisService.setCacheMap(key, cache);
        }
        // 阅读量自增
        redisService.incrementCacheMapValue(key, "viewNum", 1L);
        // 返回回答列表
        LambdaQueryWrapper<Answer> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Answer::getQuestionId, id);
        List<Answer> answers = answerMapper.selectList(wrapper);
        answers.forEach(answer -> {
            // 判断是否收藏
            String favorKey = RedisKeys.ANSWER_FAVOR.join(answer.getId().toString());
            if (!redisService.hasKey(favorKey)) {
                LambdaQueryWrapper<AnswerAttention> answerAttentionWrapper = new LambdaQueryWrapper<>();
                answerAttentionWrapper.eq(AnswerAttention::getId, answer.getId());
                Set<Long> dataSet = answerAttentionMapper.selectList(answerAttentionWrapper).stream().map(AnswerAttention::getUserId).collect(Collectors.toSet());
                redisService.setCacheSet(favorKey, dataSet);
            }
            answer.setIsCollect(redisService.getCacheSet(favorKey).contains(SecurityContextHolder.getUserId()));
            // 获取父回答
            if (answer.getParentId() != null) {
                answer.setParent(answerMapper.selectById(answer.getParentId()));
            }
        });
        // 阅读量、关注量
        question.setAnswerList(answers);
        Map<String, Object> cache = redisService.getCacheMap(key);
        question.setViewNum((Integer) cache.get("viewNum"));
        question.setCount((Integer) cache.get("count"));
        // 查询关注状态
        String favorKey = initFavor(id);
        Set<Long> favorCacheSet = redisService.getCacheSet(favorKey);
        Long userId = SecurityContextHolder.getUserId();
        question.setIsAttention(favorCacheSet.contains(userId));
        return question;
    }

    @Override
    public void questionPersistence() {
        /// 阅读、关注数
        // 获取 redis 数据
        String statusKey = RedisKeys.QUESTION_STATUS_HASH.join("*");
        List<Question> questions = redisService.keys(statusKey).stream().map(k -> {
                    Map<String, Object> cacheMap = redisService.getCacheMap(k);
                    Question question = new Question();
                    question.setId((Long) cacheMap.get("id"));
                    question.setCount((Integer) cacheMap.get("count"));
                    question.setZanCount((Integer) cacheMap.get("zanCount"));
                    question.setViewNum((Integer) cacheMap.get("viewNum"));
                    return question;
                }
        ).collect(Collectors.toList());
        // 存入 MySQL
        this.updateBatchById(questions);
        /// 关注用户
        questionAttentionMapper.delete(new QueryWrapper<>());
        String favorKey = RedisKeys.QUESTION_FAVOR.join("*");
        redisService.keys(favorKey).forEach(k -> {
            Long id = Long.valueOf(k.substring(k.lastIndexOf(":") + 1));
            redisService.getCacheSet(k).forEach(v -> questionAttentionMapper.insert(new QuestionAttention(id, (Long) v)));
        });
    }

    @Override
    public void focus(Long id) {
        // 获取 redis 数据
        String key = initFavor(id);
        // 修改 redis 的状态
        Set<Long> cacheSet = redisService.getCacheSet(key);
        Long userId = SecurityContextHolder.getUserId();
        if (cacheSet.contains(userId)) {
            throw new ServiceException("这个问题已经被关注过了");
        }
        redisService.addCacheSetValue(key, userId);
        // 修改关注数
        String statusKey = RedisKeys.QUESTION_STATUS_HASH.join(id.toString());
        redisService.incrementCacheMapValue(statusKey, "count", 1L);
    }

    @Override
    public void unfocus(Long id) {
        // 获取 redis 数据
        String key = initFavor(id);
        // 修改 redis 的状态
        Set<Long> cacheSet = redisService.getCacheSet(key);
        Long userId = SecurityContextHolder.getUserId();
        if (!cacheSet.contains(userId)) {
            throw new ServiceException("这个问题还没有被关注过");
        }
        redisService.deleteCacheSetValue(key, userId);
        // 修改关注数
        String statusKey = RedisKeys.QUESTION_STATUS_HASH.join(id.toString());
        redisService.incrementCacheMapValue(statusKey, "count", -1L);
    }

    @Override
    public void reSendQuestionMessage() {
        long now = System.currentTimeMillis();
        long max = now - 60*1000;
        String key = RedisKeys.MQ_MESSAGE.join("question");
        Set set = redisService.rangeCacheZsetByScore(key, 0, max);
        for (Object o : set) {
            String message = (String) o;
            amqpTemplate.convertAndSend("questionExchange", "", message);
        }
    }

    @Override
    public Long giveLike(Long id) {
        // 自身点赞次数 + 1
        String zanKey = RedisKeys.QUESTION_ZAN.join(SecurityContextHolder.getUserId().toString(), id.toString());
        if (!redisService.hasKey(zanKey)) {
            redisService.setCacheObject(zanKey, 0, DateUtil.getDayBetween(DateUtil.getEndTime4day(), new Date()), TimeUnit.SECONDS);
        }
        if (redisService.incrementCacheObjectValue(zanKey, 1L) > 5) {
            throw new ServiceException("每天只能点赞五次");
        }
        // 修改点赞数
        String statusKey = RedisKeys.QUESTION_STATUS_HASH.join(id.toString());
        if (!redisService.hasKey(statusKey)) {
            // 去数据库查询
            Question question = baseMapper.selectById(id);
            Map<String, Object> cacheMap = redisService.getCacheMap(statusKey);
            cacheMap.put("zanCount", question.getZanCount());
            cacheMap.put("viewNum", question.getViewNum());
            cacheMap.put("count", question.getCount());
            cacheMap.put("id", question.getId());
            redisService.setCacheMap(statusKey, cacheMap);
        }
        return redisService.incrementCacheMapValue(statusKey, "zanCount", 1L);
    }

    /**
     * 收藏初始化
     * @param id 问题id
     * @return 键
     */
    private String initFavor(Long id) {
        // 获取 redis 数据
        String key = RedisKeys.QUESTION_FAVOR.join(id.toString());
        // 如果 redis 没有该问题，去 MySQL 查询数据，同步到 redis
        if (!redisService.hasKey(key)) {
            LambdaQueryWrapper<QuestionAttention> wrapper = new LambdaQueryWrapper<>();
            wrapper.select(QuestionAttention::getUserId).eq(QuestionAttention::getId, id);
            Set<Long> userIds = questionAttentionMapper.selectList(wrapper).stream().map(QuestionAttention::getUserId).collect(Collectors.toSet());
            userIds.add(-1L);
            redisService.setCacheSet(key, userIds);
        }
        return key;
    }
}
